using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;

namespace TXLooker.Common
{
	public enum MessageLogging
	{
		/// <summary>
		/// Write Last message as first line in log file
		/// </summary>
		LastMsgToUp,
		/// <summary>
		/// Write Last message as last line in log file
		/// </summary>
		LastMsgToDown
	}

	/// <summary>
	/// Summary description for Logging.
	/// </summary>
	public class Logging
	{
		/// <summary>
		/// 
		/// </summary>
		public string CustomLogFilePath
		{
			get { return this.m_logFilePath;  }
			set { this.m_logFilePath = value; }
		}
		private string m_logFilePath = string.Empty;

		/// <summary>
		/// max custom log size. By default size is equal to 'int.MaxValue'. So we have restriction
		/// </summary>
		public int MaxCustomLogFileSize
		{
			get { return this.m_customLogSize;  }
			set
			{
				this.m_customLogSize = value < 0 ? int.MaxValue : value;
			}
		}
		private int m_customLogSize = int.MaxValue;

		public MessageLogging CustomMsgLogging
		{
			get { return this.m_MessageLogging;  }
			set { this.m_MessageLogging = value; }
		}
		private MessageLogging m_MessageLogging = MessageLogging.LastMsgToUp;

		public Logging()
		{ }
		public Logging( string customLogFilePath ) : this()
		{
			this.CustomLogFilePath = customLogFilePath;
		}
		public Logging( string customLogFilePath, int maxCustomLogFileSize ) : this( customLogFilePath )
		{
			this.MaxCustomLogFileSize = maxCustomLogFileSize;
		}

		/// <summary>
		/// We need synhronize access to the log file so we use attribute [MethodImpl(MethodImplOptions.Synchronized)] <=> lock(this)
		/// </summary>
		/// <param name="message"></param>
		[MethodImpl(MethodImplOptions.Synchronized)]
		public void WriteToCustomLog( string message )
		{
			message += System.Environment.NewLine;

            byte[] mdata = System.Text.Encoding.Default.GetBytes(message);
			int mlen = Math.Min(mdata.Length, this.MaxCustomLogFileSize);

			byte[] fdata = null;
			int flen = 0;

			using( FileStream fs = new FileStream(this.CustomLogFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite) )
			{				
				//we have restriction for log file: 'MaxCustomLogFileSize' is integer.. so long convert to int
				flen = Math.Min(this.MaxCustomLogFileSize - mlen, (int)fs.Length);
				fdata = new byte[flen];

				long offset = 0;
				switch( this.CustomMsgLogging )
				{
					case MessageLogging.LastMsgToDown:
						offset = fs.Length - flen;
						break;
					case MessageLogging.LastMsgToUp:
						offset = 0;
						break;
					default:
						throw new NotImplementedException();
				}

				fs.Seek(offset, SeekOrigin.Begin);
				fs.Read(fdata, 0, flen);
			}

			using( MemoryStream ms = new MemoryStream() )
			{
				switch( this.CustomMsgLogging )
				{
					case MessageLogging.LastMsgToUp:
						ms.Write(mdata, 0, mlen);
						ms.Write(fdata, 0, flen);
						break;
					case MessageLogging.LastMsgToDown:
						ms.Write(fdata, 0, flen);
						ms.Write(mdata, 0, mlen);
						break;
					default:
						throw new NotImplementedException();
				}

				using( FileStream fs = new FileStream(this.CustomLogFilePath, FileMode.Create, FileAccess.ReadWrite) )
				{				
					fs.Write( ms.GetBuffer(), 0, (int)ms.Length );
				}
			}

		}
		public void WriteToCustomLog( Exception ex )
		{
			this.WriteToCustomLog( ex.ToString() );
		}

		public void WriteToEventLog( string entry, string eventLogName, EventLogEntryType entryType )
		{
			if( !EventLog.SourceExists(eventLogName) )
				EventLog.CreateEventSource(eventLogName, eventLogName);

			EventLog.WriteEntry(eventLogName, entry, entryType);			
		}
		public void WriteToEventLog( Exception entry, string eventLogName, EventLogEntryType entryType )
		{
			this.WriteToEventLog( entry.ToString(), eventLogName, entryType );
		}
	}
}
